﻿using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.Runtime;
using SkiaSharp;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using LightCAD.MathLib;

namespace LightCAD.Drawing.Actions
{
    public class XLineAction : ElementAction
    {
        public static LcCreateMethod[] CreateMethods;

        static XLineAction()
        {
            CreateMethods = new LcCreateMethod[1];
            CreateMethods[0] = new LcCreateMethod()
            {
                Name = "2P",
                Description = "两点创建直线",
                Steps = new LcCreateStep[]
                {
                    new LcCreateStep { Name=  "Step0", Options= "指定点或 [水平(H)/垂直(V)/角度(A)/二等分(B)/偏移(O)]：" },
                    new LcCreateStep { Name=  "Step1", Options= "指定通过点：" },
                }
            };
        }

        internal static void Initilize()
        {
            ElementActions.XLine = new XLineAction();
            LcDocument.ElementActions.Add(BuiltinElementType.XLine, ElementActions.XLine);
        }

        private Vector2 originPoint { get; set; }
        private Vector2 thruPoint { get; set; }
        private PointInputer inputer { get; set; }

        private XLineAction() { }
        public XLineAction(IDocumentEditor docEditor) : base(docEditor)
        {
            this.commandCtrl.WriteInfo("命令：XLine");
        }

        public async void ExecCreate(string[] args = null)
        {
            this.StartCreating();
            this.inputer = new PointInputer(this.docEditor);
            var curMethod = CreateMethods[0];
        Step0:
            var step0 = curMethod.Steps[0];
            var result0 = await inputer.Execute(step0.Options);

            if (inputer.isCancelled)
            {
                this.Cancel();
                goto End;
            }

            if (result0.ValueX == null)
            {
                if (result0.Option != null)
                {

                }
                else
                {
                    goto Step1;
                }
            }
            this.originPoint = (Vector2)result0.ValueX;
        Step1:
            var step1 = curMethod.Steps[1];
            var result1 = await inputer.Execute(step1.Options);
            if (inputer.isCancelled)
            {
                this.Cancel();
                goto End; ;
            }
            if (result1.ValueX == null)
            {
                if (result1.Option == " ")
                {
                    goto End;
                }
                else if (result1.Option != null)
                {
                    this.commandCtrl.WriteInfo(SR.PointError);
                    goto Step1;
                }
                else
                {
                    goto Step1;
                }
            }

            this.thruPoint = (Vector2)result1.ValueX;
            this.CreateXLine();

            goto Step1;
        End:
            this.inputer = null;
            this.EndCreating();
        }

        public override void Cancel()
        {
            base.Cancel();
            this.vportRt.SetCreateDrawer(null);
            this.originPoint = null;
            this.thruPoint = null;
        }

        public void CreateXLine()
        {
            if (this.originPoint != null && this.thruPoint != null)
            {
                this.docRt.Document.ModelSpace.AddXLine(this.originPoint, this.thruPoint);
            }
        }

        public override void DrawAuxLines(SKCanvas canvas)
        {
            if (originPoint != null)
            {
                var mp = this.vportRt.PointerMovedPosition.ToVector2d();
                var wcs_mp = this.vportRt.ConvertScrToWcs(mp);
                DrawXLine(canvas, originPoint, wcs_mp);
            }
        }

        public override void DrawTemp(SKCanvas canvas)
        {
            //if (this.originPoint != null)
            //{
            //    for (var i = 0; i < this.points.Count; i++)
            //    {
            //        var p = this.points[i];
            //        DrawXLine(canvas, this.originPoint, p);
            //    }
            //}
        }
        private void DrawXLine(SKCanvas canvas, Vector2 p0, Vector2 p1)
        {
            if (p0.Equals(p1))
                return;

            var box = this.vportRt.Renderer.GetWcsClipBox();

            var xlineDir = (p1 - p0).Normalize();
            var xline = new LcXLine(p0, xlineDir);

            var interPs = LcGeoUtils.IntersectXLineBox(xline, box);

            if (interPs.Count < 2)
            {
                return;
            }
            else if (interPs.Count > 2)
            {

            }
            //var interP = interPs.OrderByDescending(P => Vector2d.Distance(p0, P)).FirstOrDefault();

            var sk_pre = this.vportRt.ConvertWcsToScr(interPs[0]).ToSKPoint();
            var sk_p = this.vportRt.ConvertWcsToScr(interPs[1]).ToSKPoint();
            //get Layer color 
            using (var paint = new SKPaint { Color = SKColors.Red })
            {
                canvas.DrawLine(sk_pre, sk_p, paint);
            }
        }

        public override void Draw(SKCanvas canvas, LcElement element, Matrix3 matrix)
        {
            var xline = element as LcXLine;
            var box = this.vportRt.Renderer.GetWcsClipBox();
            var interPs = LcGeoUtils.IntersectXLineBox(xline, box);

            if (interPs.Count < 2)
            {
                return;
            }
            else if (interPs.Count > 2)
            {

            }
            var mstart = matrix.MultiplyPoint(interPs[0]);
            var mend = matrix.MultiplyPoint(interPs[1]);
            var start = this.vportRt.ConvertWcsToScr(mstart).ToSKPoint();
            var end = this.vportRt.ConvertWcsToScr(mend).ToSKPoint();

            bool isDragCopy = (matrix != Matrix3.Zero);
            var pen = this.GetDrawPen(xline, isDragCopy);

            canvas.DrawLine(start, end, pen);
        }
        public override ControlGrip[] GetControlGrips(LcElement element)
        {
            var line = element as LcXLine;
            var grips = new List<ControlGrip>();
            var gripStart = new ControlGrip
            {
                Element = line,
                Name = "Start",
                Position = line.StartPoint
            };
            grips.Add(gripStart);
            var gripEnd = new ControlGrip
            {
                Element = line,
                Name = "End",
                Position = line.StartPoint + (line.Direction * 100)
            };
            grips.Add(gripEnd);
            return grips.ToArray();
        }

        private string _gripName;
        private Vector2 _position;
        private LcXLine _line;
        public override void SetDragGrip(LcElement element, string gripName, Vector2 position, bool isEnd)
        {
            var line = element as LcXLine;
            _line = line;
            if (!isEnd)
            {
                _gripName = gripName;
                _position = position;
            }
            else
            {
                if (gripName == "Start")
                    line.Set(startPoint: position);
                else if (gripName == "End")
                {
                    line.Set(dir: (position - line.StartPoint).Normalize());
                }
            }
        }

        public override void DrawDragGrip(SKCanvas canvas)
        {
            //if (_line == null) return;

            //var start = this.vportRt.ConvertWcsToScr(_line.Start);
            //if (_gripName == "Start")
            //    start = this.vportRt.ConvertWcsToScr(_position);

            //var end = this.vportRt.ConvertWcsToScr(_line.End);
            //if (_gripName == "End")
            //    end = this.vportRt.ConvertWcsToScr(_position);

            //canvas.DrawLine(start.ToSKPoint(), end.ToSKPoint(), Constants.draggingPen);
        }
    }
}
